
package edu.hm.devcamp.presentation.views;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.drawable.Drawable;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import edu.hm.devcamp.R;
import edu.hm.devcamp.presentation.LocationListenerImpl;
import edu.hm.devcamp.presentation.activities.PoiMap;
import edu.hm.devcamp.providers.Poi;
import edu.hm.devcamp.providers.Pois;
import edu.hm.devcamp.util.GeoUtils;

public class ARPoiView extends View {

    private static final String TAG = "ARPoiView";

    /**
     * the complete list of POIs
     */
    private List<Poi> mPois;

    /**
     * the list of POIs we want to display
     */
    private List<Poi> mDrawingPois = new ArrayList<Poi>();

    /**
     * the ar view's context
     */
    private Context mContext;

    /**
     * the sensor manager
     */
    private SensorManager mSensorManager;

    /**
     * the angle of the device to the magnetic north pole in a right-turning 360
     * degree manner
     */
    private float mAngle;

    /**
     * the view angle of the camera
     */
    private static float mCameraAngle;

    public static void setCameraAngle(float cameraAngle) {
        mCameraAngle = cameraAngle;
    }

    public void setPois(List<Poi> pois) {
        mPois = pois;
    }

    public ARPoiView(Context context, AttributeSet attrs) {
        super(context, attrs);

        init(context);
    }

    public ARPoiView(Context context, List<Poi> pois, float cameraAngle) {
        super(context);
        init(context);
        mPois = pois;
        mCameraAngle = cameraAngle;
    }

    public ARPoiView(Context context) {
        super(context);
        init(context);
    }

    private void init(Context context) {
        mContext = context;

        // register the needed sensors (orientation)
        mSensorManager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE);
        mSensorManager.registerListener(listener,
                mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD),
                SensorManager.SENSOR_DELAY_FASTEST);
        mSensorManager.registerListener(listener,
                mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
                SensorManager.SENSOR_DELAY_FASTEST);

        invalidate();
    }

    private Bitmap mCulture;
    private Bitmap mLibrary;
    private Bitmap mPlayground;
    private Bitmap mRecycleCenter;
    private Bitmap mRecycleSmall;
    private Bitmap mTaxi;
    private Bitmap mToilet;

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        int canvasHeight = canvas.getHeight();
        int canvasWidth = canvas.getWidth();

        int drawingCenter;

        if (mCulture == null) {
            mCulture = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.bavaria);
        }
        if (mLibrary == null) {
            mLibrary = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.library);
        }
        if (mPlayground == null) {
            mPlayground = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.playground);
        }
        if (mRecycleCenter == null) {
            mRecycleCenter = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.recycle_center);
        }
        if (mRecycleSmall == null) {
            mRecycleSmall = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.recycle_small);
        }
        if (mTaxi == null) {
            mTaxi = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.taxi);
        }
        if (mToilet == null) {
            mToilet = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.toilet);
        }

        Paint paint;
        for (int i = 0; i < mDrawingPois.size(); i++) {

            Poi poi = mDrawingPois.get(i);

            drawingCenter = (int)(canvasWidth * poi.anglePercentage);

            Log.d(TAG, "drawing center = " + drawingCenter);

            paint = new Paint();
            paint.setTextSize(28);
            
            drawingCenter -= paint.measureText(poi.name) / 2;
            
            Bitmap drawBitmap = mCulture;
            if(poi.category.equals(Pois.categories.culturalCenter.toString())){
                drawBitmap = mCulture;
            } else if(poi.category.equals(Pois.categories.library.toString())){
                drawBitmap = mLibrary;
            } else if(poi.category.equals(Pois.categories.playground.toString())){
                drawBitmap = mPlayground;
            } else if(poi.category.equals(Pois.categories.recycleCenter.toString())){
                drawBitmap = mRecycleCenter;
            } else if(poi.category.equals(Pois.categories.recycleSmall.toString())){
                drawBitmap = mRecycleSmall;
            } else if(poi.category.equals(Pois.categories.taxiStop.toString())){
                drawBitmap = mTaxi;
            } else if(poi.category.equals(Pois.categories.toilet.toString())){
                drawBitmap = mToilet;
            }                 
                
            canvas.drawBitmap(drawBitmap, drawingCenter, canvasHeight * 0.66f - drawBitmap.getHeight() * 2, paint);
            canvas.drawText(poi.name, drawingCenter, canvasHeight *0.66f, paint);
        }

        sortPois();
        updateDrawingList();
        invalidate();
    }

    private SensorEventListener listener = new SensorEventListener() {

        float[] magnitude_values;

        boolean sensorReady = false;

        float[] accelerometer_values;

        float[] actual_vals = new float[3];

        @Override
        public void onAccuracyChanged(Sensor sensor, int accuracy) {
        }

        
        private float mOldAngle = 0;
        @Override
        public void onSensorChanged(SensorEvent event) {
            switch (event.sensor.getType()) {
                case Sensor.TYPE_MAGNETIC_FIELD:
                    magnitude_values = event.values.clone();
                    sensorReady = true;
                    break;
                case Sensor.TYPE_ACCELEROMETER:
                    accelerometer_values = event.values.clone();
                    break;
            }

            if (magnitude_values != null && accelerometer_values != null && sensorReady) {
                sensorReady = false;

                float[] R = new float[16];
                float[] I = new float[16];

                SensorManager.getRotationMatrix(R, I, this.accelerometer_values,
                        this.magnitude_values);

                float[] outR = new float[16];
                SensorManager.remapCoordinateSystem(R, SensorManager.AXIS_X, SensorManager.AXIS_Z,
                        outR);
                SensorManager.getOrientation(outR, actual_vals);

                mAngle = (float)(actual_vals[0] * (180 / Math.PI));
                if (mAngle < 0) {
                    mAngle = 360 + mAngle;
                }
                
                // simple stabilisation
                if(Math.abs(mOldAngle - mAngle) < 20f){
                    mAngle = mOldAngle;

                    
                }
            }
        }
    };

    /**
     * fills the mDrawingPois-list with POIs that should be drawn.
     */
    private void updateDrawingList() {

        mDrawingPois.clear();

        for (Poi poi : mPois) {
            if (LocationListenerImpl.currentLocation != null) { // as soon as we
                                                                // are having a
                                                                // position
                if (GeoUtils.isInViewAreaUpdatePoi(mCameraAngle, mAngle, poi)) { // and
                                                                                 // if
                                                                                 // it
                                                                                 // is
                                                                                 // in
                                                                                 // our
                                                                                 // view,
                    mDrawingPois.add(poi); // we draw it.
                }
            }
        }

        if (PoiMap.LOG_D) {
            Log.d(TAG, "updated drawing list");
        }
    }

    private void sortPois() {
        Collections.sort(mPois, new Comparator<Poi>() {
            @Override
            public int compare(Poi a, Poi b) {
                if (a.distance > b.distance) {
                    return 1;
                } else if (a.distance < b.distance) {
                    return -1;
                }
                return 0;
            }
        });
        
        for(int i = 50; i < mPois.size(); i++){
            mPois.remove(i);
        }
    }
}
